package easy

import (
	"errors"
	"math"
	"reflect"
	"strconv"
)

const (
	TypeNull   = 0
	TypeFloat  = 1
	TypeInt    = 2
	TypeString = 3
)

var (
	uid = uint64(0)
	gid = uint64(0)
	tid = uint64(0)
)

// 拆分给定的区间为num个区间
// begin 开始值
// end 结束值
// num 区间数量
// result 结果数组
// err 错误信息
func SplitRange(begin, end, num int) (result []int) {
	if begin > end {
		return []int{begin, end}
	}
	total := end - begin + 1
	if total <= num {
		return []int{begin, end}
	}
	perLoop := total / num
	remainder := total % num
	if remainder != 0 {
		perLoop++
	}
	result = make([]int, 0, num+1)
	result = append(result, begin)
	for i := 0; i < num; i++ {
		start := begin + i*perLoop
		end1 := start + perLoop
		if i < remainder {
			end1++
		}
		if end1 > end {
			end1 = end
		}
		result = append(result, end1)
	}
	return result
}

// 设置数据落到量程内
func Range[T float32 | float64 | int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64](x, low, high T) T {
	x = max(x, low)
	x = min(x, high)
	return x
}

// 乘法,数组中的每个数都乘一个系数
func Multi[T float32 | float64 | int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64](vals []T, fk T) {
	for i := range vals {
		vals[i] *= fk
	}
}

/**
 * @description:x 在 begin 和end之间 (包含begin)
 * @param {*}
 * @return {*}
 */
func Between[T float32 | float64 | int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64](x, begin, end T) bool {
	return x >= begin && x < end
}

/**
 * @description: float转字符串
 * @param {float64} f
 * @return {*}
 */
func Ftoa(f float64) string {
	num := f - float64(int64(f))
	if math.Abs(num) < 0.000001 {
		return strconv.FormatInt(int64(f), 10)
	}
	return strconv.FormatFloat(f, 'f', -1, 64)
}

/**
 * @description: float转字符串
 * @param {float64} f
 * @return {*}
 */
func FtoaWithPrec(f float64, prec int) string {
	num := f - float64(int64(f))
	if math.Abs(num) < 0.000001 {
		return strconv.FormatInt(int64(f), 10)
	}
	return strconv.FormatFloat(f, 'f', prec, 64)
}

/**
 * @description: 字符串转换float
 * @param {string} s
 * @return {*}
 */
func Atof(s string) (f float64, err error) {
	return strconv.ParseFloat(s, 64)
}

type Float64 float64

func NewFloat64(f float64) Float64 {
	return Float64(f)
}

// ToString 浮点类型转字符串
func (f Float64) ToString() string {
	return Ftoa(float64(f))
}

// ToString 浮点类型转字符串
func (f Float64) String() string {
	return Ftoa(float64(f))
}

// Round 保留有效位数
func Round(value float64, decimal int) float64 {
	return math.Round(value*math.Pow10(decimal)) / math.Pow10(decimal)
}

// Round 保留有效位数
func RoundSlow(value float64, decimal int) float64 {
	v := strconv.FormatFloat(float64(value), 'f', decimal, 64)
	fval, _ := strconv.ParseFloat(v, 64)
	return fval
}

// FloatEqual 浮点型相等判断
func FloatEqual(a, b float64) bool {
	return math.Abs(a-b) < 0.00001
}

func GetType(arg any) byte {
	switch arg.(type) {
	case bool:
		return TypeInt
	case float32:
		return TypeFloat
	case float64:
		return TypeFloat
	case int:
		return TypeInt
	case int8:
		return TypeInt
	case int16:
		return TypeInt
	case int32:
		return TypeInt
	case int64:
		return TypeInt
	case uint:
		return TypeInt
	case uint8:
		return TypeInt
	case uint16:
		return TypeInt
	case uint32:
		return TypeInt
	case uint64:
		return TypeInt
	case string:
		return TypeString
	default:
	}
	return TypeNull
}

func GetReflectType(typ reflect.Type) byte {
	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
	}
	switch typ.Kind() {
	case reflect.Bool:
		return TypeInt
	case reflect.Float32:
		return TypeFloat
	case reflect.Float64:
		return TypeFloat
	case reflect.Int:
		return TypeInt
	case reflect.Int8:
		return TypeInt
	case reflect.Int16:
		return TypeInt
	case reflect.Int32:
		return TypeInt
	case reflect.Int64:
		return TypeInt
	case reflect.Uint:
		return TypeInt
	case reflect.Uint8:
		return TypeInt
	case reflect.Uint16:
		return TypeInt
	case reflect.Uint32:
		return TypeInt
	case reflect.Uint64:
		return TypeInt
	case reflect.String:
		return TypeString
	default:
	}
	return TypeNull
}

// GetFloat64 获取浮点值
func GetFloat64(arg interface{}) (fval float64, err error) {
	switch f := arg.(type) {
	case bool:
		if f {
			fval = 1
		} else {
			fval = 0
		}
	case float32:
		fval = float64(f)
	case float64:
		fval = f
	case int:
		fval = float64(f)
	case int8:
		fval = float64(f)
	case int16:
		fval = float64(f)
	case int32:
		fval = float64(f)
	case int64:
		fval = float64(f)
	case uint:
		fval = float64(f)
	case uint8:
		fval = float64(f)
	case uint16:
		fval = float64(f)
	case uint32:
		fval = float64(f)
	case uint64:
		fval = float64(f)
	case string:
		fval, err = strconv.ParseFloat(f, 64)
	default:
		err = errors.New("计算结果类型错误")
	}
	return
}

// GetFloat64 获取浮点值
func GetFloat64WithType(arg any) (fval float64, typ string, err error) {
	switch f := arg.(type) {
	case bool:
		if f {
			fval = 1
		} else {
			fval = 0
		}
		typ = "bool"
	case float32:
		fval = float64(f)
		typ = "float32"
	case float64:
		fval = f
		typ = "float64"
	case int:
		fval = float64(f)
		typ = "int"
	case int8:
		fval = float64(f)
		typ = "int8"
	case int16:
		fval = float64(f)
		typ = "int16"
	case int32:
		fval = float64(f)
		typ = "int32"
	case int64:
		fval = float64(f)
		typ = "int64"
	case uint:
		fval = float64(f)
		typ = "uint"
	case uint8:
		fval = float64(f)
		typ = "uint8"
	case uint16:
		fval = float64(f)
		typ = "uint16"
	case uint32:
		fval = float64(f)
		typ = "uint32"
	case uint64:
		fval = float64(f)
		typ = "uint64"
	case string:
		typ = "string"
		fval, err = strconv.ParseFloat(f, 64)
	default:
		err = errors.New("计算结果类型错误")
	}
	return
}

func MakeTypeValue(fval float64, typ string) (v any, err error) {
	switch typ {
	case "bool":
		if fval == 0 {
			return false, nil
		}
		return true, nil
	case "float32":
		return float32(fval), nil
	case "float64":
		return fval, nil
	case "int":
		return int(fval), nil
	case "int8":
		return int8(fval), nil
	case "int16":
		return int16(fval), nil
	case "int32":
		return int32(fval), nil
	case "int64":
		return int64(fval), nil
	case "uint":
		return uint(fval), nil
	case "uint8":
		return uint8(fval), nil
	case "uint16":
		return uint16(fval), nil
	case "uint32":
		return uint32(fval), nil
	case "uint64":
		return uint64(fval), nil
	}
	return nil, errors.New("unknown type of " + typ)
}

// GetInt64 获取浮点值
func GetInt64(arg interface{}) (ival int64, err error) {
	switch f := arg.(type) {
	case bool:
		if f {
			ival = 1
		} else {
			ival = 0
		}
	case float32:
		ival = int64(f)
	case float64:
		ival = int64(f)
	case int:
		ival = int64(f)
	case int8:
		ival = int64(f)
	case int16:
		ival = int64(f)
	case int32:
		ival = int64(f)
	case int64:
		ival = f
	case uint:
		ival = int64(f)
	case uint8:
		ival = int64(f)
	case uint16:
		ival = int64(f)
	case uint32:
		ival = int64(f)
	case uint64:
		ival = int64(f)
	case string:
		ival, err = strconv.ParseInt(f, 10, 64)
	default:
		err = errors.New("计算结果类型错误")
	}
	return
}
